#include "timer_wheel.h"

#include <memory>

using namespace TimerWheel;


SingleWheel::SingleWheel(uint32_t scales, uint32_t uint_ms, const std::string &name) {
    m_name = name;
    m_scales = scales;
    m_slots.reserve(scales);
    m_unit_ms = uint_ms;
    m_current_idx = 0;
    m_higher_wheel = m_lower_wheel = nullptr;
    m_slots = std::vector<std::list<TimerPtr>>(m_scales);
}

void SingleWheel::set_higher_wheel(SingleWheel *higher_tw) {
    m_higher_wheel = higher_tw;
}

void SingleWheel::set_lower_wheel(SingleWheel *lower_tw) {
    m_lower_wheel = lower_tw;
}

int64_t SingleWheel::get_current_time() {
    int64_t time = m_current_idx * m_unit_ms;
    if (m_lower_wheel != nullptr) {
        time += m_lower_wheel->get_current_time();
    }
    return time;
}

bool SingleWheel::insert_timer(const TimerPtr& timer) {
    // 由高级轮向低级轮递归查找添加
    int64_t lower_time = 0;
    if (m_lower_wheel != nullptr) {
        lower_time = m_lower_wheel->get_current_time();
    }
    int64_t extend_time = timer->expiry_ms - get_now_timestamp() + lower_time;
    if (extend_time >= m_scales * m_unit_ms && m_lower_wheel != nullptr) {
        return false;
    } else if (extend_time >= m_unit_ms ){
        size_t idx = (m_current_idx + extend_time / m_unit_ms) % m_scales;
        m_slots[idx].push_back(timer);
        return true;
    } else if (m_lower_wheel != nullptr) {
        m_lower_wheel->insert_timer(timer);
        return true;
    } else {
        // lowest
        m_slots[m_current_idx].push_back(timer);
        return true;
    }
}

void SingleWheel::step() {
    m_current_idx += 1;
    if (m_current_idx < m_scales) {
        return;
    }

    m_current_idx = m_current_idx % m_scales;
    if (m_higher_wheel != nullptr) {
        m_higher_wheel->step();
        std::list<TimerPtr> higher_slot = std::move(m_higher_wheel->move_slot());
        for (const TimerPtr& t : higher_slot) {
            insert_timer(t);
        }
    }

}

std::list<TimerPtr> SingleWheel::move_slot() {
    std::list<TimerPtr> cur_slot = std::move(m_slots[m_current_idx]);
    return cur_slot;
}




TimerWheels::TimerWheels(uint32_t minstep_ms) {
    m_is_stop = false;
    m_minstep_ms = minstep_ms;
}

void TimerWheels::append_wheel(uint32_t scales, uint32_t unit_ms, const std::string &name) {
    WheelPtr new_wheel = std::make_shared<SingleWheel>(scales, unit_ms, name);
    if (!m_wheels.empty()){
        WheelPtr lower_wheel = m_wheels.back();
        lower_wheel->set_higher_wheel(new_wheel.get());
        new_wheel->set_lower_wheel(lower_wheel.get());
    }
    m_wheels.push_back(new_wheel);
}

WheelPtr TimerWheels::get_highest_wheel() {
    if (m_wheels.empty()){
        return {};
    } else {
        return m_wheels.back();
    }
}

WheelPtr TimerWheels::get_lowest_wheel() {
    if (m_wheels.empty()){
        return {};
    } else {
        return m_wheels.front();
    }
}

void TimerWheels::start() {
    assert(!m_wheels.empty() && m_minstep_ms >= 50);
    m_thread = std::thread([this](){run();});
}

void TimerWheels::stop() {
    {
        std::lock_guard<std::mutex> lock(m_mutex);
        m_is_stop = true;
    }
    if (m_thread.joinable()){
        m_thread.join();
    }
}

void TimerWheels::run() {
    while (!m_is_stop) {
        std::this_thread::sleep_for(std::chrono::milliseconds(m_minstep_ms));
        std::lock_guard<std::mutex> lock(m_mutex);
        // 从最低级开始移动
        WheelPtr lowest_wheel = get_lowest_wheel();
        lowest_wheel->step();
        std::list<TimerPtr> cur_slot = std::move(lowest_wheel->move_slot());
        for (const TimerPtr & timer : cur_slot) {
            // 取消的任务
            if (del_timer_ids.count(timer->id)){
                del_timer_ids.erase(timer->id);
                continue;
            }

            // 执行任务
            timer->task();

            // 周期任务
            if (timer->repeated) {
                timer->expiry_ms += timer->interval_ms;
                get_highest_wheel()->insert_timer(timer);
            }
        }
    }
}

void TimerWheels::add_timer(int32_t id, int64_t timeout_ms, const TimerTask &task) {
    assert(!m_wheels.empty());
    std::lock_guard<std::mutex> lock(m_mutex);
    int64_t expires_ms = get_now_timestamp() + timeout_ms;
    get_highest_wheel()->insert_timer(std::make_shared<Timer>(id, expires_ms, 0, task));
}

void TimerWheels::add_repeated_timer(int32_t id, int64_t interval_ms, const TimerTask &task) {
    assert(!m_wheels.empty());
    std::lock_guard<std::mutex> lock(m_mutex);
    int64_t expires_ms = get_now_timestamp() + interval_ms;
    get_highest_wheel()->insert_timer(std::make_shared<Timer>(id, expires_ms, interval_ms, task));
}

void TimerWheels::del_timer(uint32_t id) {
    std::lock_guard<std::mutex> lock(m_mutex);
    del_timer_ids.insert(id);
}






